<?php

namespace origin;

/**
 * 依赖注入类 (DependenceInjection AS Di)
 * @explain 依赖注入 控制反转 单例模式
 * @author dece <decezz@qq.com>
 */
class Di implements \ArrayAccess
{
    /**
     * 实例
     */
    public static $instance = null;
    /**
     * 容器
     */
    protected static $container = [];
    /**
     * 命中次数
     */
    protected static $hit_count = [];

    /**
     * 构造
     */
    public function __construct()
    {
    }

    /**
     * 获取依赖注入类的实例
     */
    public static function instance()
    {
        if (self::$instance == null) {
            self::$instance = new static();
        }
        return self::$instance;
    }

    /**
     * 容器列表
     */
    public static function container_list()
    {
        return array_keys(self::$container);
    }

    /**
     * 添加容器
     * @param string    $name   容器名称
     * @param mixed     $value  依赖容器
     * @param mixed     $param  回调函数的参数
     * @return bool
     */
    public static function set( string $name , $value , $param = null )
    {
        if (!is_string($name)) {
            throw new \Exception("Argument 1 must be an string");
        }
        // 设定命中
        self::$hit_count[$name] = 0;
        // 添加容器
        self::$container[$name] = [
            'value' => $value,
            'param' => $param,
        ];
        return true;
    }

    /**
     * 获取容器
     * @param string $name 容器名称
     */
    public static function get( string $name )
    {
        if (!array_key_exists($name, self::$container)) {
            return null;
        }
        // 提取变量
        extract(self::$container[$name]);

        return self::startService($value, $param);
    }

    /**
     * 加载依赖
     * @param mixed $service 依赖
     * @param mixed $params  参数
     */
    protected static function startService( $service , $params )
    {
        if ($service instanceof \Closure) {
            return call_user_func_array($service, [$params]);
        } elseif (is_array($service) && count($service) == 2 && is_callable($service[0])) {
            list($class, $method) = $service;
            return call_user_func_array([(new $class()), $method], $params);
        }
        return $service;
    }

    /**
     * 释放容器
     * @param string $name 容器名称
     * @return void
     */
    public static function reset( string $name )
    {
        unset(self::$hit_count[$name]);
        unset(self::$container[$name]);
        return ;
    }

    /**
     * 添加容器
     * @param string   $name   容器名称
     * @param mixed    $value  依赖容器
     */
    public function __set( $name , $value )
    {
        return self::set($name, $value);
    }

    /**
     * 获取容器
     * @param string $name 容器名称
     */
    public function __get( $name )
    {
        return self::set($name);
    }

    // ================================ ArrayAccess 数组式访问 ================================
    public function offsetSet( $offset , $value )
    {
        return self::set($offset, $value);
    }

    public function offsetGet( $offset )
    {
        return self::get($offset);
    }

    public function offsetUnset( $offset )
    {
        return self::reset($offset);
    }

    public function offsetExists( $offset )
    {
        return isset($this->container[$offset]);
    }
    // ================================ ArrayAccess 数组式访问 ================================
}